Skip to content

fix(dead-code): preserve generic @return tags in `RemoveReturnTagIn…#8183

Merged
TomasVotruba merged 1 commit into
rectorphp:mainfrom
maartenpaauw:fix/dead-code-generics
Jul 13, 2026
Merged

fix(dead-code): preserve generic @return tags in `RemoveReturnTagIn…#8183
TomasVotruba merged 1 commit into
rectorphp:mainfrom
maartenpaauw:fix/dead-code-generics

Conversation

@maartenpaauw

Copy link
Copy Markdown
Contributor

This fixes RemoveReturnTagIncompatibleWithNativeTypeRector incorrectly stripping @return self<T> and @return ClassName<T> docblocks when the native return type is self.

Problem

Given a templated class:

/**
 * @template TAdded
 * @template TRemoved
 */
final readonly class Changes
{
    /**
     * @param list<TAdded> $added
     * @param list<TRemoved> $removed
     */
    private function __construct(
        public array $added,
        public array $removed,
    ) {
    }

    /**
     * @param list<TAdded> $added
     * @param list<TRemoved> $removed
     *
     * @return self<TAdded, TRemoved>
     */
    public static function create(array $added, array $removed): self
    {
        return new self($added, $removed);
    }
}

The rule would remove @return self<TAdded, TRemoved> because it considered it incompatible with the native self return type. However, the annotation is not redundant, because it narrows the return type with template parameters that PHP's native type system cannot express. PHPStan and Psalm rely on these annotations for generic type inference.

Fix

Added an early bail-out when $returnTagValueNode->type is an instance of GenericTypeNode. This catches all @return Foo<T>, @return self<T>, and @return static<T> patterns at the PHPDoc AST level before any expensive type resolution occurs.

…compatibleWithNativeTypeRector`

The rule incorrectly removed `@return self<T>` and `@return ClassName<T>` annotations when the native return type was `self`. These annotations are not incompatible, because they carry template parameters that the native type cannot express. PHPStan and Psalm rely on them for generic type inference.

Add an early bail-out when the `@return` type node is a `GenericTypeNode`, which covers all parameterized return types (`self<T>`, `static<T>`, `Foo<T>`).
@TomasVotruba TomasVotruba merged commit 653ec23 into rectorphp:main Jul 13, 2026
65 checks passed
@TomasVotruba

Copy link
Copy Markdown
Member

Looks good 👌

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants